import * as cc from 'cc';
import { VMConfig } from './VMConfig';
import { VMBaseAttr, VMLabelAttr, VMCustomAttr, VMNodeAttr, VMProgressAttr, VMSpriteAttr, VMButtonAttr, VMEventAttr, VMChildAttr, VMEntity, VMChildrenAttr, VMUITransform, VMUIOpacity, VMColor, VMComponentAttr } from './VMEntity';
import { VMFatory } from './VMFactory';
import { VM } from './VMMgr';

declare let CC_DEV;
class GVMCenter {

    private static id = 0;
    public VMTag(target: IMVVM) {
        if (!target._vmTag) {
            target._vmTag = `VM-AUTO-${GVMCenter.id}`;
            GVMCenter.id++;
        }
    }

    add(data: any, targetOrTag: IMVVM | string, tag?: string) {
        if (!tag) {
            if (typeof targetOrTag === 'string') {
                tag = targetOrTag;
            } else {
                this.VMTag(targetOrTag);
                tag = targetOrTag._vmTag;
            }
        }
        if (tag == undefined || tag == null) {
            console.error(`VMCenter-> tag is `, tag);
            return;
        }
        VM.add(data, tag);
    }

    remove(target: IMVVM, tag?: string) {
        VM.remove(tag || target._vmTag);
        this._vmUnBind(target);
    }
    /**
     * 通过过滤器进行移除绑定
     * @param target 
     * @param filter 
     * @returns 
     */
    removeBindWithFilter(target: IMVVM,filter?: (entity: VMEntity,index: number, array: VMEntity[])=> boolean): boolean{
        
        let _entities = target._vmEntitys.filter(filter);
        if (!_entities.length) {
            cc.log(`VMCenter-> 没有找到需要移除的实体`);
            return false;
        }
        for (let i = _entities.length - 1; i >= 0; i--) {
            this._vmUnbindPath(_entities[i]);
            target._vmEntitys.splice(i, 1);
        }
        return true;
    }
    /**
     * 移除指定的组件 或 节点的绑定
     * @param target 
     * @param comp 
     * @returns 
     */
    removeBind(target: IMVVM, comp: cc.Component | cc.Node): boolean {
       return this.removeBindWithFilter(target,(val: VMEntity,index: number, array: VMEntity[])=>{
            let node = comp instanceof cc.Node ? comp : comp.node;
            return val.node === node;
        });
    }

    

    private VMBase(target: IMVVM, comp: cc.Node, vmAnyAttr: VMBaseAttr, entityName: string) {

        // this.lazyCheckWatchPath(vmAnyAttr.watchPath,target.constructor.name,propertyKey);
        // vmAnyAttr.propertyKey = propertyKey;
        !vmAnyAttr.options && (vmAnyAttr.options = {});
        !!entityName && (vmAnyAttr.options.entityName = entityName);
        // if(Array.isArray(__vmAnyAttr.watchPath)){
        //     // 如果监听的是两个值，则必定是用的模板模式
        //     __vmAnyAttr.templateMode = true;
        // }

        this._vmBind(target, comp, vmAnyAttr);
    }

    Label(target: IMVVM, label: cc.Label | cc.Node, vmAnyAttr: VMLabelAttr) {
        vmAnyAttr.vmName = 'VMLabel';
        vmAnyAttr.requireComponent = cc.Label;
        // !vmAnyAttr.options && (vmAnyAttr.options = {});
        // (vmAnyAttr.options.entityName = "cc.Label");
     
        if (Array.isArray(vmAnyAttr.watchPath)) {
            // 如果监听的是两个值，则默认是用的模板模式
            if (vmAnyAttr.templateMode === undefined) {
                vmAnyAttr.templateMode = true;
            }
        }
        if(label instanceof cc.Component){
            label = label.node;
        }
        // this._vmBind(target, label, vmAnyAttr)
        this.VMBase(target,label,vmAnyAttr,"cc.Label");
    }

    Custom<T = any>(target: IMVVM, type: cc.__private._types_globals__Constructor<T>, comp: cc.Component | cc.Node, __vmAnyAttr: VMCustomAttr<T>,entityName?: string) {
        __vmAnyAttr.vmName = 'VMCustom';
        __vmAnyAttr.execComponent = type;
        __vmAnyAttr.requireComponent = type;
        if(comp instanceof cc.Component){
            comp = comp.node;
        }
        return this.VMBase(target, comp, __vmAnyAttr, entityName || 'vm.Custom');
    }

    Component<T = any>(target: IMVVM, type: cc.__private._types_globals__Constructor<T>, comp: cc.Component | cc.Node, __vmAnyAttr: VMComponentAttr<T>,entityName?: string){

        
        return this.Custom(target, type, comp, __vmAnyAttr, entityName || 'vm.Component');
    }


    Progress(target: IMVVM, comp: cc.ProgressBar | cc.Node, __vmAnyAttr: VMProgressAttr) {
        __vmAnyAttr.vmName = 'VMProgress';
        __vmAnyAttr.requireComponent = cc.ProgressBar;
        if(comp instanceof cc.Component){
            comp = comp.node;
        }
        // return this.VMBase(target, comp, __vmAnyAttr,"cc.ProgressBar");
        return this.Component(target,cc.ProgressBar,comp,__vmAnyAttr as any, 'cc.ProgressBar');
    }

    Slider(target: IMVVM, comp: cc.Slider | cc.Node, __vmAnyAttr: VMProgressAttr) {
        __vmAnyAttr.vmName = 'VMProgress';
        __vmAnyAttr.requireComponent = cc.Slider;
        if(comp instanceof cc.Component){
            comp = comp.node;
        }
        // return this.VMBase(target, comp, __vmAnyAttr,"cc.Slider");
        return this.Component(target,cc.Slider,comp,__vmAnyAttr as any, 'cc.Slider');
    }

    Sprite(target: IMVVM, comp: cc.Sprite | cc.Node, __vmAnyAttr: VMSpriteAttr) {
        __vmAnyAttr.vmName = 'VMSprite';
        // __vmAnyAttr.requireComponent = cc.Sprite;
        // 添加默认加载资源的方法
        if (!__vmAnyAttr.formator) {
            __vmAnyAttr.formator = (opts) => {
                return new Promise<cc.SpriteFrame>((resolve, reject) => {
                    if (!opts.newValue) {
                        resolve(null);
                        return;
                    }
                    cc.resources.load(opts.newValue,cc.SpriteFrame, (err, spriteFrame: cc.SpriteFrame) => {
                        if (err) {
                            return resolve(null);
                        }
                        resolve(spriteFrame);
                    });
                });
            };
        }
        // return this.VMBase(target, comp, __vmAnyAttr, 'cc.Sprite');

        return this.Component(target,cc.Sprite,comp,__vmAnyAttr as any, 'cc.Sprite');
    }

    /**
     * ButtonClick 是对 watchPath 中的数据进行修改，必须实现 operation 方法
     * @param target 
     * @param comp 
     * @param __vmAnyAttr 
     * @returns 
     */
    ButtonClick(target: IMVVM, comp: cc.Button | cc.Node, __vmAnyAttr: VMButtonAttr) {
        __vmAnyAttr.vmName = 'VMButton';
        __vmAnyAttr.requireComponent = cc.Button;
        if(comp instanceof cc.Component){
            comp = comp.node;
        }
        return this.VMBase(target, comp, __vmAnyAttr as any, 'vm.ButtonClick');
    }

    Event(target: IMVVM, comp: cc.Component | cc.Node, __vmAnyAttr: VMEventAttr) {
        __vmAnyAttr.vmName = 'VMEvent';
        if(comp instanceof cc.Component){
            comp = comp.node;
        }
        return this.VMBase(target, comp, __vmAnyAttr, 'vm.Event');
    }

    Node(target: IMVVM, node: cc.Node, __vmAnyAttr: VMNodeAttr) {
        __vmAnyAttr.vmName = 'VMNode';
        if (!__vmAnyAttr.property) {
            __vmAnyAttr.property = 'active';
        }
        return this.VMBase(target, node, __vmAnyAttr, 'cc.Node');
    }

    // Child(target: IMVVM, node: cc.Node, __vmAnyAttr: VMChildAttr) {
    //     __vmAnyAttr.vmName = 'VMChild';
    //     return this.VMBase(target, node, __vmAnyAttr, 'vm.Child');
    // }

    Children(target: IMVVM, node: cc.Node, __vmAnyAttr: VMChildrenAttr) {
        __vmAnyAttr.vmName = 'VMChildren';
        if (!__vmAnyAttr.property) {
            __vmAnyAttr.property = 'active';
        }
        
        // @ts-ignore
        __vmAnyAttr.controlChildren = true;
        return this.VMBase(target, node, __vmAnyAttr, 'vm.Children');
    }

    Color(target: IMVVM, node: cc.Component | cc.Node,__vmAnyAttr: VMColor){
        __vmAnyAttr.vmName = 'VMColor';
        // @ts-ignore
        if (!__vmAnyAttr.property) {
            // @ts-ignore
            __vmAnyAttr.property = 'color';
        }
        
        return this.Component(target,cc.Renderable2D ,node, __vmAnyAttr as any);
    }

    UITransform(target: IMVVM, node: cc.Component | cc.Node, __vmAnyAttr: VMUITransform){
        __vmAnyAttr.vmName = 'VMUITransform';
       return this.Component(target,cc.UITransform,node,__vmAnyAttr as any);
    }

    UIOpacity(target: IMVVM, node: cc.Component | cc.Node, __vmAnyAttr: VMUIOpacity){
        __vmAnyAttr.vmName = 'VMUIOpacity';
        if (!__vmAnyAttr.property) {
            __vmAnyAttr.property = 'opacity';
        }
       return this.Component(target,cc.UIOpacity,node,__vmAnyAttr as any);
    }


    private _vmBind(target: IMVVM, node: cc.Node, _tmpObserverAttr: VMBaseAttr) {

        if (!node) {

            console.warn(`VMCenter:  [${_tmpObserverAttr.vmName}] component is null`);
            return;
        }

        this.VMTag(target);

        !target._vmEntitys && (target._vmEntitys = []);

        let _observerAttr = cc.instantiate(_tmpObserverAttr);
        if (_observerAttr.formator) {
            _observerAttr.formator.bind(this);
        }


        this._vmFormatWatchPath(target, _observerAttr);

        // // 检查依赖的组件
        // if(_observerAttr.requireComponent != undefined){
        //     let requireComponent = typeof _observerAttr.requireComponent == 'string' ? _observerAttr.requireComponent : cc.js.getClassName(_observerAttr.requireComponent);

        //     if(_property.__classname__ != requireComponent){
        //         console.warn(`VMCenter:  [${_observerAttr._propertyKey}] ==> is not [${requireComponent}] Component, can't add [${_observerAttr.vmName}] in list`);                            
        //         return;
        //     }                            
        // }
        if(!_observerAttr?.options?.entityName){
            console.warn(`VMCenter:  [${node.name}] ==> 没有设置 entityName 不能加入到绑定列表`);                            
            return;
        }
        let _componentName = _observerAttr.options.entityName;
        let _vmEntityClass = VMFatory.getVMEntity(_componentName);
        if (!_vmEntityClass) {
            console.warn(`VMCenter: VMFatory can't find [${_componentName}], can't add [${_observerAttr.vmName}] in list`);
            return
        }
        let _vmEntity = new _vmEntityClass() as VMEntity;
        // _vmEntity.component = _observerAttr.requireComponent ? node?.getComponent(_observerAttr.requireComponent as any) : node as any;
        _vmEntity.node = node;
        _vmEntity.observerAttr = _observerAttr;

        let check = _vmEntity.onCheckProperty();
        if (!check) {
            // @ts-ignore
            console.warn(`VMCenter:  [${this.__proto__.__classname__}] ==>  [${node.name}] on Check Property failed !! can't add [${_observerAttr.vmName}] in list`);
            return;
        }

        _vmEntity.controllerUserComponent = target;
        target._vmEntitys.push(_vmEntity);
        _vmEntity.onValueInit();
        this._vmBindPath(_vmEntity);
    }

    private _vmUnBind(target: IMVVM) {
        if (target._vmEntitys) {
            for (let i = 0; i < target._vmEntitys.length; i++) {
                const _vmEntity: VMEntity = target._vmEntitys[i];
                this._vmUnbindPath(_vmEntity);
            }
            target._vmEntitys.length = 0;
        }
    }

    private _vmUnbindPath(_vmEntity: VMEntity) {
        if (VMConfig.DEBUG) {
            console.log(`VMCenter: node: ${_vmEntity.observerAttr._propertyKey} unbind ${_vmEntity.observerAttr.watchPath}`);
        }
        _vmEntity.unbindPath();
    }

    private _vmFormatWatchPath(target: IMVVM, _observerAttr: VMBaseAttr) {
        let path = _observerAttr.watchPath;
        if (typeof path == 'string') {
            //遇到特殊 path 就优先替换路径
            if (path.startsWith('*')) {
                _observerAttr.watchPath = path.replace('*', target._vmTag);
            }
        } else if (Array.isArray(path)) {
            for (let j = 0; j < path.length; j++) {
                const _path = path[j];
                if (_path.startsWith('*')) {
                    path[j] = _path.replace('*', target._vmTag);
                }
            }
            _observerAttr.watchPath = path;
        }
    }

    private _vmBindPath(_vmEntity: VMEntity) {
        if (VMConfig.DEBUG) {
            console.log(`VMCenter: node: ${_vmEntity.observerAttr._propertyKey} bind ${_vmEntity.observerAttr.watchPath} ${_vmEntity.constructor.name}`);
        }
        _vmEntity.bindPath();
    }

    private devCheckPathAndProperty(target: IMVVM, _watchPath: string | string[],property: string){
        if(!CC_DEV){
            return;
        }



    }

    // 检查监听路径
    private lazyCheckWatchPath(_watchPath: string | string[], clazz, proprety) {
        let _watchPaths = Array.isArray(_watchPath) ? _watchPath : [_watchPath];
        for (let i = 0; i < _watchPaths.length; i++) {
            const _tmpWatchPath = _watchPaths[i];
            if (_tmpWatchPath.startsWith('*')) {
                let idx = _tmpWatchPath.indexOf('.');
                if (idx == -1) {
                    console.warn(`VMDecorator-> ${clazz} ${proprety} watchPath error`);
                    return false;
                }
            }
        }
        return true;
    }

}
export let VMCenter = new GVMCenter();